﻿using System;
using System.Collections.Generic;
using System.Xml;
using SdmxMl.Common;
using SdmxMl.Structure;
using SdmxMl.Manager;
using SdmxMl.Helper;

namespace GeoPlugIn
{
    public class SdmxHgde
    {
        private static string validFrom = "1960-01-01";
        private static string agencyGEWO = "CH1_RN";

        private HgdeHistory hgdeHist;
        private CodeListType clCanton;
        private CodeListType clDistrict;
        private CodeListType clCommune;
        private TextProvider msgProvider;

        private CodeListType[] arrCodeList;

        private SmManager smSnapshot;

        public SdmxHgde (IReader ir, TextProvider prov)
        {
            msgProvider = prov;
            hgdeHist = ir as HgdeHistory;
            if (hgdeHist == null)
                throw new ApplicationException("Invalid history received in converter.");

            arrCodeList = new CodeListType[3];

            // Container to keep info for generating Snapshot
            smSnapshot = new SmManager();
        }

        private MultiLang UpdateNameWithDate(string tag)
        {
            //Name internationalized
            MultiLang name = msgProvider.GetInternationalizedTextOf(tag);
            foreach (string lg in LangSupport.SupportedLanguages)
                name.UpdateForLanguage(lg, name.GetForLanguage(lg) + " (" + hgdeHist.VersionDate + ")");
            return name;
        }

        public void ConvertCanton(string folder)
        {
            smSnapshot = new SmManager();

            CodeListType clt = new CodeListType();
            clt.AgencyId = agencyGEWO;
            clt.Id = "CL_HGDE_" + HgdeHistory.ArrayAliasRef[0];
            clt.ValidFrom = validFrom;

            //Name internationalized
            clt.Name = UpdateNameWithDate("CANTON");

            // All codes
            clt.CodeList.HasHierarchy = false;
            foreach (CsvCanton canton in hgdeHist.CantonDico.Values)
            {
                CodeType c = new CodeType();
                c.Id = canton.Code;
                c.Name.UpdateDefaultText(canton.OfficialTitle);
                Annotation ann = new Annotation("ABBREV");
                ann.Text.UpdateDefaultText(canton.ShortTitle);
                if (ann.Text.IsEmpty == false)
                    c.AnnotationList.Add(ann);
                clt.CodeList.Add(c);
            }

            smSnapshot.PutArtefact(SdmxArtefactType.CodeLists, clt);
            PersistCodelist(folder, clt);
            arrCodeList[0] = clCanton = clt;
        }

        public void ConvertDistrict(string folder)
        {
            CodeListType clt = new CodeListType();
            clt.AgencyId = agencyGEWO;
            clt.Id = "CL_HGDE_" + HgdeHistory.ArrayAliasRef[1];
            clt.ValidFrom = validFrom;

            //Name internationalized
            clt.Name = UpdateNameWithDate("DISTRICT");

            // All codes
            clt.CodeList.HasHierarchy = false;

            foreach (CsvDistrict district in hgdeHist.DistrictDico.Values)
            {

                CodeType c = new CodeType();
                c.Id = district.NoHistory;
                c.Name.UpdateDefaultText(district.OfficialTitle);

                //OFS code
                Annotation ann = new Annotation("CODE_OFS");
                ann.Text.UpdateDefaultText(district.Code);
                c.AnnotationList.Add(ann);

                // Abbrev
                if ((string.IsNullOrEmpty(district.ShortTitle) == false && district.ShortTitle != district.OfficialTitle))
                {
                    ann = new Annotation("ABBREV");
                    ann.Text.UpdateDefaultText(district.ShortTitle);
                    c.AnnotationList.Add(ann);
                }

                if (district.Inscription != null && district.Inscription.IsEmpty == false && district.Inscription.No != "1000" && district.Inscription.No != "100")
                {
                    ann = new Annotation("INSCRIPTION");
                    if (string.IsNullOrEmpty(district.Inscription.MutType) == false)
                        ann.Title = district.Inscription.MutType;
                    ann.Text.UpdateDefaultText(district.Inscription.No);
                    c.AnnotationList.Add(ann);
                }

                if (district.Radiation != null && district.Radiation.IsEmpty == false)
                {
                    ann = new Annotation("RADIATION");
                    if (string.IsNullOrEmpty(district.Radiation.MutType) == false)
                        ann.Title = district.Radiation.MutType;
                    ann.Text.UpdateDefaultText(district.Radiation.No);
                    c.AnnotationList.Add(ann);
                }

                if (district.TypeRecord != "15") // Special Annotation
                {
                    ann = new Annotation("REC_TYPE");
                    ann.Title = district.TypeRecord;
                    if (district.TypeRecord == "16")
                        ann.Text = msgProvider.GetInternationalizedTextOf("REC_TYPE_16");
                    else
                        ann.Text = msgProvider.GetInternationalizedTextOf("REC_TYPE_17");

                    c.AnnotationList.Add(ann);
                }


                clt.CodeList.Add(c);
            }

            smSnapshot.PutArtefact(SdmxArtefactType.CodeLists, clt);
            PersistCodelist(folder, clt);
            arrCodeList[1] = clDistrict = clt;


        }

        public void ConvertCommunes(string folder)
        {
            CodeListType clt = new CodeListType();
            clt.AgencyId = agencyGEWO;
            clt.Id = "CL_HGDE_" + HgdeHistory.ArrayAliasRef[2];
            clt.ValidFrom = validFrom;

            //Name internationalized
            clt.Name = UpdateNameWithDate("COMMUNE");

            // All codes
            clt.CodeList.HasHierarchy = false;

            foreach (CsvMunicipality mut in hgdeHist.MunicipalityList)
            {

                CodeType c = new CodeType();
                c.Id = mut.NoHistory;
                c.Name.UpdateDefaultText(mut.OfficialTitle);

                //OFS code
                Annotation ann = new Annotation("CODE_OFS");
                ann.Text.UpdateDefaultText(mut.Code);
                c.AnnotationList.Add(ann);

                // Abbrev
                if ((string.IsNullOrEmpty(mut.ShortTitle) == false && mut.ShortTitle != mut.OfficialTitle))
                {
                    ann = new Annotation("ABBREV");
                    ann.Text.UpdateDefaultText(mut.ShortTitle);
                    c.AnnotationList.Add(ann);
                }

                if (mut.Inscription != null && mut.Inscription.IsEmpty == false && mut.Inscription.No != "1000" && mut.Inscription.No != "100")
                {
                    ann = new Annotation("INSCRIPTION");
                    if (string.IsNullOrEmpty(mut.Inscription.MutType) == false)
                        ann.Title = mut.Inscription.MutType;
                    ann.Text.UpdateDefaultText(mut.Inscription.No);
                    c.AnnotationList.Add(ann);
                }

                if (mut.Radiation != null && mut.Radiation.IsEmpty == false)
                {
                    ann = new Annotation("RADIATION");
                    if (string.IsNullOrEmpty(mut.Radiation.MutType) == false)
                        ann.Title = mut.Radiation.MutType;
                    ann.Text.UpdateDefaultText(mut.Radiation.No);
                    c.AnnotationList.Add(ann);
                }

                if (mut.TypeRecord != "11") // Special Annotation
                {
                    ann = new Annotation("REC_TYPE");
                    ann.Title = mut.TypeRecord;
                    if (mut.TypeRecord == "12")
                        ann.Text = msgProvider.GetInternationalizedTextOf("REC_TYPE_12");
                    else
                        ann.Text = msgProvider.GetInternationalizedTextOf("REC_TYPE_13");

                    c.AnnotationList.Add(ann);
                }

                clt.CodeList.Add(c);
            }

            smSnapshot.PutArtefact(SdmxArtefactType.CodeLists, clt);
            PersistCodelist(folder, clt);
            arrCodeList[2] = clCommune = clt;
        }

        #region Hierarchy

        public void CreateHierarchy(string folder)
        {
            // Create srtefact
            HierarchicalCodelistType he = new HierarchicalCodelistType();
            he.Id = "HCL_HGDE_HIST";
            he.AgencyId = agencyGEWO;
            he.ValidFrom = validFrom;
            he.ValidTo = hgdeHist.VersionDate;

            //Name Internationalized
            he.Name = UpdateNameWithDate("HISTORY_GDE");

            // Create Hierarchy container
            HierarchyType heType = new HierarchyType(he.CodelistRefList);
            heType.Id = "HR_" + he.Id.Substring(4);
            heType.Name.UpdateDefaultText("Hierarchy");
            he.HierarchyList.Clear();
            he.HierarchyList.Add(heType);

            // Create references
            int aliasCd = 0;
            foreach (CodeListType clt in arrCodeList)
            {
                // Create references
                CodelistRefType che = new CodelistRefType();
                che.AgencyId = clt.AgencyId;
                che.Id = clt.Id;
                che.Alias = HgdeHistory.ArrayAliasRef[aliasCd++];
                che.Version = clt.Version;
                he.CodelistRefList.Add(che);

                LevelType level = new LevelType();
                level.Id = "LV_" + che.Alias;
                foreach (string lg in LangSupport.SupportedLanguages)
                    level.Name.UpdateForLanguage(lg, clt.Name.GetForLanguage(lg));
                level.CodingType.TextType = TextTypeType.Integer;
                level.Order = aliasCd;
                heType.LevelList.Add(level);
            }

            //All cantons with it's hierarchy
            string from, to;
            foreach (CsvCanton canton in hgdeHist.CantonDico.Values)
            {
                CodeRefType heRefcodeCanton = new CodeRefType();
                heRefcodeCanton.CodeID = canton.Code;
                heRefcodeCanton.CodelistAliasRef = HgdeHistory.ArrayAliasRef[0];
                heType.CodeRefList.Add(heRefcodeCanton);

                List<CsvDistrict> distriList = GetDistrictOfCanton(canton, hgdeHist.DistrictDico);
                foreach (CsvDistrict district in distriList)
                {
                    CodeRefType heRefcodeDistrict = new CodeRefType();
                    heRefcodeDistrict.CodeID = district.NoHistory;
                    heRefcodeDistrict.CodelistAliasRef = HgdeHistory.ArrayAliasRef[1];
                    heRefcodeCanton.CodeRefList.Add(heRefcodeDistrict);

                    List<CsvMunicipality> aMunicipalityList = GetMunicipalitiesOfDistrict(district, hgdeHist.MunicipalityList);
                    foreach (CsvMunicipality municip in aMunicipalityList)
                    {
                        CodeRefType heRefcodeCommune = new CodeRefType();
                        heRefcodeCommune.CodeID = municip.NoHistory;
                        heRefcodeCommune.CodelistAliasRef = HgdeHistory.ArrayAliasRef[2];
                        heRefcodeDistrict.CodeRefList.Add(heRefcodeCommune);

                        // Validity interval
                        from = ToIsoDate(municip.Inscription.Date);
                        to = ToIsoDate(municip.Radiation.Date);
                        if (from.Length > 0)
                            heRefcodeCommune.ValidFrom = from;
                        if (to.Length > 0)
                            heRefcodeCommune.ValidTo = to;
                    }
                    // Validity interval
                    from = ToIsoDate(district.Inscription.Date);
                    to = ToIsoDate(district.Radiation.Date);
                    if (from.Length > 0)
                        heRefcodeDistrict.ValidFrom = from;
                    if (to.Length > 0)
                        heRefcodeDistrict.ValidTo = to;
                }
                // Validity interval
                from = ToIsoDate(canton.SysUpdateDt);
                if (from.Length > 0)
                    heRefcodeCanton.ValidFrom = from;
            }

            SmManager sm = new SmManager();
            sm.PutArtefact(SdmxArtefactType.HierarchicalCodelists, he);
            smSnapshot.PutArtefact(SdmxArtefactType.HierarchicalCodelists, he);

            XmlDocument xDoc = sm.GetAsDocument();
            if (string.IsNullOrEmpty(folder) == false)
                xDoc.Save(folder + "\\" + he.FullIdent + ".xml");
        }
        #endregion

        #region SnapShot

        public void CreateSnapShot(string folder)
        {
            HgdeSnapshot snapshot = new HgdeSnapshot(msgProvider, smSnapshot);
            snapshot.Generate(DateTime.Parse(hgdeHist.VersionDate), hgdeHist.VersionSdmx);

            SmManager sm = new SmManager();
            foreach (Artefact ar in snapshot.ArmCodelist.ArtefactList)
                sm.PutArtefact(SdmxArtefactType.CodeLists, ar);
            sm.PutArtefact(SdmxArtefactType.HierarchicalCodelists, snapshot.ArmHierarchy.ArtefactList[0]);
            XmlDocument xDoc = sm.GetAsDocument();
            if (string.IsNullOrEmpty(folder) == false)
            {
                string fname = folder + "\\" + snapshot.ArmHierarchy.ArtefactList[0].FullIdent + ".xml";
                xDoc.Save(fname);
            }

            ReferenceManager.TreeMgr.LoadSdmxArtefact(null, true, xDoc);
        }

        #endregion

        private void PersistCodelist(string folder, CodeListType clt)
        {
            SmManager sm = new SmManager();
            sm.PutArtefact(SdmxArtefactType.CodeLists, clt);
            XmlDocument xDoc = sm.GetAsDocument();
            if (string.IsNullOrEmpty(folder) == false)
            {
                string fname = folder + "\\" + clt.FullIdent + ".xml";
                xDoc.Save(fname);
            }

            ReferenceManager.TreeMgr.LoadSdmxArtefact(null, true, xDoc);

        }

        private string ToIsoDate(string date)
        {
            string ret = string.Empty;
            if (string.IsNullOrEmpty(date) == false)
            {
                DateTime dt = DateTime.Parse(date);
                ret = dt.ToString("yyyy-MM-dd");
            }
            return ret;
        }

        private List<CsvDistrict> GetDistrictOfCanton(CsvCanton canton, Dictionary<string, CsvDistrict> districtDico)
        {
            List<CsvDistrict> aDistrictList = new List<CsvDistrict>();
            foreach (CsvDistrict district in districtDico.Values)
            {
                if (district.TypeRecord != "17" && // territoire non attribué
                    district.Canton == canton)
                    aDistrictList.Add(district);
            }
            return aDistrictList;
        }

        private List<CsvMunicipality> GetMunicipalitiesOfDistrict(CsvDistrict district, List<CsvMunicipality> municipalityList)
        {
            List<CsvMunicipality> aMunicipalityList = new List<CsvMunicipality>();
            foreach (CsvMunicipality municip in municipalityList)
            {
                if (municip.TypeRecord == "11" && // commune politique
                    municip.District == district)
                    aMunicipalityList.Add(municip);
            }
            return aMunicipalityList;
        }

    }
}
